#pragma once

namespace My {

inline const ActionQueue & Doc::GetActions() const
{
	return m_Actions; 
}

inline ActionQueue & Doc::GetActions()
{
	return m_Actions; 
}

template <typename T>
TypedSelection<T>::TypedSelection() :
	m_Update(false),
	m_Changed(false)
{
}

template <typename T>
TypedSelection<T>::~TypedSelection()
{
	Clear();
}

template <typename T>
bool TypedSelection<T>::IsSelected(const T & obj) const
{
	return m_Objects.find(const_cast<T *>(&obj)) 
		!= m_Objects.end();
}

template <typename T>
void TypedSelection<T>::Select(T & obj)
{
	if (m_Objects.insert(&obj).second) {
		obj.InvalidateSelectionState();
		if (m_Update)
			m_Changed = true;
		else
			Selection::Changed();

	}
}


template <typename T>
void TypedSelection<T>::Deselect(T & obj)
{
	if (m_Objects.erase(&obj) != 0) {
		obj.InvalidateSelectionState();
		if (m_Update)
			m_Changed = true;
		else
			Selection::Changed();
	}
}

template <typename T>
bool TypedSelection<T>::IsEmpty() const
{
	return m_Objects.empty();
}

template <typename T>
void TypedSelection<T>::Clear()
{
	if (m_Objects.empty())
		return;

	ObjectSet tmp;
	tmp.swap(m_Objects);

	for (ObjectSet::iterator it = tmp.begin(); it != tmp.end(); ++it)
		(* it)->InvalidateSelectionState();

	if (m_Update) 
		m_Changed = true;
	else
		Selection::Changed();
}

template <typename T>
void TypedSelection<T>::BeginUpdate()
{
	m_Update = true;
	m_Changed = false;
}

template <typename T>
void TypedSelection<T>::EndUpdate()
{
	m_Update = false;
	if (m_Changed)
		Selection::Changed();
}

template <typename T>
void TypedSelection<T>::ProcessEvent(Event & e)
{
	if (e.Is<CommandEvent>()) {
		CommandEvent & cmd = e.As<CommandEvent>();
		ObjectSet tmp = m_Objects; // "this" may be deleted during processing
		for (ObjectSet::iterator it = tmp.begin(); it != tmp.end(); ++it)
		{
			CommandEvent tmp(cmd.m_nID);
			(* it)->ProcessEvent(tmp);
			cmd.m_Handled |= tmp.m_Handled;
		}
	} else
	if (e.Is<UpdateCommandUIEvent>()) {
		UpdateCommandUIEvent & cmd = e.As<UpdateCommandUIEvent>();
		GroupCmdUI cmdUI;
		for (ObjectSet::iterator it = m_Objects.begin(); it != m_Objects.end(); ++it)
		{
			UpdateCommandUIEvent tmp(cmd.m_nID, &cmdUI);
			(* it)->ProcessEvent(tmp);
			cmd.m_Handled |= tmp.m_Handled;
		}
		if (cmdUI.m_bEnableChanged)
			cmd.m_pCmdUI->Enable(cmdUI.m_Enabled);
	}
}

template <typename T>
bool IsSelected(const T & obj)
{
	TypedSelection<T> * pSel = 
		dynamic_cast<TypedSelection<T> *>(&GetSelection());
	return pSel != 0 && pSel->IsSelected(obj);
}

template <typename T>
void Select(T & obj, bool on)
{
	TypedSelection<T> * pSel = 
		dynamic_cast<TypedSelection<T> *>(&GetSelection());
	if (on) {
		if (pSel == 0)
			SetSelection(pSel = new TypedSelection<T>);
		pSel->Select(obj);
	} else {
		if (pSel != 0)
			pSel->Deselect(obj);
	}
}

} // My
